/// @class : asperct_raioImage
/// @date : 2023-03-03 11:30
/// @name : LFC
/// @description :
import 'dart:async';
import 'dart:io';
import 'dart:typed_data';
import 'dart:ui' as ui;

import 'package:flutter/material.dart';

typedef AsyncImageWidgetBuilder<T> = Widget Function(
    BuildContext context, AsyncSnapshot<T> snapshot, String url);

typedef AsyncImageFileWidgetBuilder<T> = Widget Function(
    BuildContext context, AsyncSnapshot<T> snapshot, File file);

typedef AsyncImageMemoryWidgetBuilder<T> = Widget Function(
    BuildContext context, AsyncSnapshot<T> snapshot, Uint8List bytes);

enum AsperctRaioImageType { NETWORK, FILE, ASSET, MEMORY }

///有宽高的Image
class AsperctRaioImage extends StatelessWidget {
  String? url;
  File? file;
  Uint8List? bytes;
  final ImageProvider? provider;
  AsperctRaioImageType? type;
  AsyncImageWidgetBuilder<ui.Image>? builder;
  AsyncImageFileWidgetBuilder<ui.Image>? filebBuilder;
  AsyncImageMemoryWidgetBuilder<ui.Image>? memoryBuilder;

  AsperctRaioImage.network(url, {required Key key, required this.builder})
      : provider = NetworkImage(url),
        type = AsperctRaioImageType.NETWORK,
        url = url;

  AsperctRaioImage.file(
    this.file, {
    required Key key,
    @required this.filebBuilder,
  })  : provider = FileImage(file!),
        type = AsperctRaioImageType.FILE;

  AsperctRaioImage.asset(name, {required Key key, @required this.builder})
      : provider = AssetImage(name),
        type = AsperctRaioImageType.ASSET,
        url = name;

  AsperctRaioImage.memory(this.bytes,
      {required Key key, @required this.memoryBuilder})
      : provider = MemoryImage(bytes!),
        type = AsperctRaioImageType.MEMORY;

  @override
  Widget build(BuildContext context) {
    final ImageConfiguration config = createLocalImageConfiguration(context);
    final Completer<ui.Image> completer = Completer<ui.Image>();
    final ImageStream stream = provider!.resolve(config);
    ImageStreamListener? listener;
    listener = ImageStreamListener((ImageInfo image, bool sync) {
      completer.complete(image.image);
      stream.removeListener(listener!);
    }, onError: (Object exception, StackTrace? stackTrace) {
      completer.complete();
      if (listener != null) {
        stream.removeListener(listener);
      }
      FlutterError.reportError(FlutterErrorDetails(
        context: ErrorDescription('image failed to precache'),
        library: 'image resource service',
        exception: exception,
        stack: stackTrace,
        silent: true,
      ));
    });
    stream.addListener(listener);

    return FutureBuilder(
        future: completer.future,
        builder: (BuildContext context, AsyncSnapshot<ui.Image> snapshot) {
          if (snapshot.hasData) {
            if (type == AsperctRaioImageType.FILE) {
              if (file != null) {
                return filebBuilder!(context, snapshot, file!);
              }
            } else if (type == AsperctRaioImageType.MEMORY) {
              if (memoryBuilder != null && bytes != null) {
                return memoryBuilder!(context, snapshot, bytes!);
              }
            } else {
              if (builder != null && url != null) {
                return builder!(context, snapshot, url!);
              }
            }
          } else {
            return Container();
          }
          return Container();
        });
  }
}
